#ifndef BIJECTIONMAP_H_
#define BIJECTIONMAP_H_

#include <QMap>

template<class A, class B>
class BijectionMap
{
public:
	// constructor & destructor
	BijectionMap();
	BijectionMap(const BijectionMap<A, B> & other);
	BijectionMap(const BijectionMap<B, A> & other);
	virtual ~BijectionMap()
	{
	}
	;

	// member functions
	bool containsInA(const A & value) const;
	bool containsInB(const B & value) const;
	bool contains(const A & aValue, const B & bValue) const;
	int count() const;
	bool remove(const A & aValue);
	bool remove(const B & bValue);

	const A getAValue(const B & bValue) const;
	const B getBValue(const A & aValue) const;
	A & getAValue(const B & bValue);
	B & getBValue(const A & aValue);

	void insert(const A & aValue, const B & bValue);
	const QMap<A, B> & getMapAB() const;
	const QMap<B, A> & getMapBA() const;
	QMap<A, B> & getMapAB();
	QMap<B, A> & getMapBA();


	void clear();

private:
	// member data
	QMap<A, B> mapAB;
	QMap<B, A> mapBA;
};

template<class A, class B> BijectionMap<A, B>::BijectionMap()
{
}

template<class A, class B> BijectionMap<A, B>::BijectionMap(const BijectionMap<A, B> & other) :
	mapAB(other.mapAB), mapBA(other.mapBA)
{
}

template<class A, class B> BijectionMap<A, B>::BijectionMap(const BijectionMap<B, A> & other) :
	mapAB(other.mapBA), mapBA(other.mapAB)
{
}

template<class A, class B> bool BijectionMap<A, B>::containsInA(const A & value) const
{
	return mapAB.contains(value);
}

template<class A, class B> bool BijectionMap<A, B>::containsInB(const B & value) const
{
	return mapBA.contains(value);
}

template<class A, class B> bool BijectionMap<A, B>::contains(const A & aValue, const B & bValue) const
{
	return mapAB.contains(aValue, bValue);
}

template<class A, class B> int BijectionMap<A, B>::count() const
{
	return mapAB.count();
}

template<class A, class B> bool BijectionMap<A, B>::remove(const A & aValue)
{
	if (!containsInA(aValue)) return false;

	const B & bValue = mapAB[aValue];
	mapAB.remove(aValue);
	mapBA.remove(bValue);

	return true;

}
template<class A, class B> bool BijectionMap<A, B>::remove(const B & bValue)
{
	if (!containsInB(bValue)) return false;

	const A & aValue = mapBA[bValue];
	mapAB.remove(aValue);
	mapBA.remove(bValue);

	return true;
}
template<class A, class B> const A BijectionMap<A, B>::getAValue(const B & bValue) const
{
	if (!containsInB(bValue)) insert(A(), bValue);

	return mapBA[bValue];
}
template<class A, class B> const B BijectionMap<A, B>::getBValue(const A & aValue) const
{
	if (!containsInA(aValue)) insert(aValue, B());

	return mapAB[aValue];
}
template<class A, class B> A & BijectionMap<A, B>::getAValue(const B & bValue)
{
	if (!containsInB(bValue)) insert (A(), bValue);

	return mapBA[bValue];
}
template<class A, class B> B & BijectionMap<A, B>::getBValue(const A & aValue)
{
	if (!containsInA(aValue)) insert(aValue, B());

	return mapAB[aValue];
}
template<class A, class B> void BijectionMap<A, B>::insert(const A & aValue, const B & bValue)
{
	mapAB[aValue] = bValue;
	mapBA[bValue] = aValue;
}

template<class A, class B> const QMap<A, B> & BijectionMap<A, B>::getMapAB() const
{
	return mapAB;
}
template<class A, class B> const QMap<B, A> & BijectionMap<A, B>::getMapBA() const
{
	return mapBA;
}
template<class A, class B> QMap<A, B> & BijectionMap<A, B>::getMapAB()
{
	return mapAB;
}
template<class A, class B> QMap<B, A> & BijectionMap<A, B>::getMapBA()
{
	return mapBA;
}
template<class A, class B> void BijectionMap<A, B>::clear()
{
	mapAB.clear();
	mapBA.clear();
}

#endif /* BIJECTIONMAP_H_ */
